package com.ai.sml.action;

import java.io.IOException;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.struts2.ServletActionContext;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;

import com.ai.common.xml.bean.Output;
import com.ai.common.xml.util.ControlConstants;
import com.ai.frame.bean.InputObject;
import com.ai.frame.bean.OutputObject;
import com.ai.frame.logger.Logger;
import com.ai.frame.logger.LoggerFactory;
import com.ai.frame.util.JsonUtil;
import com.ai.sml.control.IControlService;
import com.ai.sml.service.ICacheService;
import com.ai.sml.util.CacheUtil;
import com.ai.sml.util.Constants;
import com.ai.sml.util.DateUtil;
import com.ai.sml.util.MyOwnRuntimeException;
import com.ai.sml.util.StringUtil;
import com.ai.sml.util.DateUtil.DATE_PATTERN;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

/**
 * 
 * 
 */
public abstract class BaseAction extends ActionSupport implements BeanFactoryAware{
	private static final long serialVersionUID = 1581119741116374826L;
	private static final Logger logger = LoggerFactory.getActionLog(BaseAction.class);
	private static final Log logInputObject = LogFactory .getLog("inputObjectLog");
	private transient IControlService controlService; // 前后工程调用服务
	private transient ICacheService cacheService;	// 缓存服务
	private transient InputObject inputObject;
	private transient BeanFactory factory;

	/** Get the request Object **/
	public HttpServletRequest getRequest() {
		return ServletActionContext.getRequest();
	}

	/** Get the response Object **/
	public HttpServletResponse getResponse() {
		return ServletActionContext.getResponse();
	}

	/** Get the current Session **/
	public HttpSession getSession() {
		return getRequest().getSession();
	}
	
	/** Get the current Session **/
	public HttpSession getSession(boolean arg0) {
		return getRequest().getSession(arg0);
	}

	/** Get the Servlet Context **/
	public ServletContext getServletContext() {
		return ServletActionContext.getServletContext();
	}

	/** Get the Value Stack of Struts2 **/
	public ValueStack getValueStack() {
		return ServletActionContext.getValueStack(getRequest());
	}
	
	/** Set the Bean Factory **/
	public void setBeanFactory(BeanFactory factory) {
		this.factory = factory;
	}

	/** Get the IControlService Object **/
	public IControlService getControlService() {
		return controlService;
	}

	public void setControlService(IControlService controlService) {
		this.controlService = controlService;
	}

	/** Get the ICacheService Object **/
	public ICacheService getCacheService() {
		return cacheService;
	}
	
	public void setCacheService(ICacheService cacheService) {
		this.cacheService = cacheService;
	}
	
	/** Print OutputStream to the Browser **/
	public void sendJson(String json) {
		try {
			getResponse().setContentType("text/html");
			getResponse().getWriter().print(json);
			logger.info("sendJson", json);
		} catch (IOException e) {
			logger.error("sendJson", "Exception Occured When Send Json to Client !", e);
		}
	}

	/** Get InputObject Object Encapsulated **/
	public InputObject getInputObject() {
		inputObject = (InputObject) ServletActionContext.getContext().get(ControlConstants.INPUTOBJECT);
		inputObject.getParams().put("chnlId", Constants.MERCHANT_CHNL_ID);
		inputObject.getParams().put("CHNL_ID", Constants.MERCHANT_CHNL_ID);
		String staffId = (String) SecurityUtils.getSubject().getPrincipal();
		inputObject.getParams().put("staffId", staffId);
		return inputObject;
	}

	/** Call Services and Get OutputObject Object **/
	public OutputObject getOutputObject() {
		return getOutputObject(getInputObject());
	}

	/** Call Services and Get OutputObject Object **/
	public OutputObject getOutputObject(InputObject inputObject) {
		OutputObject object = null;
		long start=System.currentTimeMillis();
		String cacheKey = inputObject.getParams().get(ControlConstants.CACHE_KEY);
		try{
			if (cacheKey == null) {
				object = this.execute(inputObject);
			} else {// OsCache
				object = getCacheService().getFromCache(cacheKey);
				if (object == null) {
					object = this.execute(inputObject);
					getCacheService().put2Cache(cacheKey, object);
				}
			}
		} catch (Exception e) {
			logger.error("getOutputObject", "getOutputObject", e);
			object = new OutputObject(ControlConstants.RETURN_CODE.SYSTEM_ERROR, e.getMessage());
		}
		long end = System.currentTimeMillis();
		//Session session = SecurityUtils.getSubject().getSession();
		//获取OutputObject出参
		Map<String,Object > outMap = new HashMap<String,Object>();
		outMap.put("returnCode", object.getReturnCode());
		outMap.put("returnMsg", object.getReturnMessage());
		outMap.put("bean", object.getBean());
		outMap.put("beans", object.getBeans());
		outMap.put("Object", object.getObject());
		//Object o = session.getAttribute("merchantInfo");
		//获取登录用户名
	/*	Map<String, String> user = null==o?null:(Map)o;
		String userName =null;
		if(null != user){
			userName = user.get("USER_LOGIN_ID");
		}*/
		//拼接log信息
		StringBuilder loginfo = new StringBuilder("");
		loginfo.append(DateUtil.date2String(new Date())+"|");
		//loginfo.append(session.getId()+"|");
		//loginfo.append(userName+"|");
		loginfo.append(getClass().getSimpleName()+"|");
		loginfo.append(inputObject.getService()+"|");
		loginfo.append(inputObject.getMethod()+"|");
		loginfo.append(inputObject.getParams()+"|");
		loginfo.append(outMap+"|");
		loginfo.append((end-start)/1000f);
		logInputObject.info(loginfo);
		return object;
	}
	
	private OutputObject execute(InputObject inputObject) {
		OutputObject outputObject = null;
		try {
			if (ControlConstants.CMS_SERVICE.equalsIgnoreCase(inputObject.getService())) {//CMS
				Object object = factory.getBean(inputObject.getService());
				Method mth = object.getClass().getMethod(inputObject.getMethod(),
						InputObject.class);
				outputObject = (OutputObject) mth.invoke(object, inputObject);
			} else {// WEBSERVICE
				outputObject = getControlService().execute(inputObject);
			}
		} catch (Exception e) {
			logger.error("", "Invoke Service Error.", inputObject.getService() + "." + inputObject.getMethod(), e);
		}
		return outputObject;
	}
	
	/**
	 * Json String Unified Conversion Method
	 * @param outputObject
	 * @return Json
	 */
	public String convertOutputObject2Json(OutputObject outputObject) {
		return convertOutputObject2Json(getInputObject(), outputObject);
	}

	/**
	 * Json String Unified Conversion Method
	 * @param outputObject
	 * @return Json
	 */
	public String convertOutputObject2Json(InputObject inputObject,OutputObject outputObject) {
		String json = "";
		if (outputObject == null || inputObject == null){
			return json;
		}

		Output output = (Output) ServletActionContext.getContext().get(ControlConstants.OUTPUT);
		try {
			// 如果配置了相应的IConvertor则执行，否则执行默认的Json转换功能
			if (output != null && StringUtil.isNotEmpty(output.getConvertor())) {
				json = JsonUtil.outputObject2Json(output.getConvertor(),
						output.getMethod(), inputObject, outputObject);
			}else{
				json = JsonUtil.outputObject2Json(outputObject);
			}
		} catch (Exception e) {
			logger.error("convertOutputObject", "Convert Output Error.", "", e);
		}
		return json;
	}
	
	public String getSequence(String tableName) throws MyOwnRuntimeException {
		if (StringUtil.isEmpty(tableName)) {
			throw new MyOwnRuntimeException("获取主键时前缀不能为空!建议传入表名");
		}
		String redisKey = "REDIS_TBL_" + tableName;
		String id = null;
		try {
			logger.info("开始获取主键 ", "key=" + redisKey);
			id = DateUtil.date2String(new Date(), DATE_PATTERN.YYYYMMDDHHMMSSSSS) + ""
					+ new DecimalFormat("#000").format(CacheUtil.incr(redisKey));
			logger.info("获取主键成功", "id=" + id);
		} catch (Exception e) {
			logger.error("使用redis获取主键失败，开始使用UUID", "key=" + redisKey, e);
			id = UUID.randomUUID().toString();
			logger.error("NOT ERROR! 主键获取成功", "key=" + redisKey + ",id=" + id);
		}
		return id;
	}
}
